﻿using System;

namespace Core
{

    //TimeSpan ts1 = new TimeSpan(dStart.Ticks);
    //TimeSpan ts2 = new TimeSpan(dEnd.Ticks);
    //TimeSpan ts = ts1.Subtract(ts2).Duration();
    //dateDiff = "{0}天{1}小时{2}分钟{3}秒".Translate(ts.Days, ts.Hours, ts.Minutes, ts.Seconds);

    /// <summary>
    /// 时间段
    /// 
    /// 参考 System.TimeSpan
    /// 
    /// 格式: 1d18h15m20s
    /// 
    /// </summary>
    public struct Period : IEquatable<Period>
    {
        /// <summary>
        /// 天
        /// </summary>
        public int Day;

        /// <summary>
        /// 小时 [0,24)
        /// </summary>
        public int Hour;

        /// <summary>
        /// 分钟 [0,60)
        /// </summary>
        public int Minute;

        /// <summary>
        /// 秒 [0,60)
        /// </summary>
        public int Second;

        private static int Parse(string str, string c, ref int idx1, ref int idx2)
        {
            int value = 0;
            idx2 = str.IndexOf(c);
            if (idx2 >= 0)
            {
                try
                {
                    value = int.Parse(str[idx1..idx2]);
                }
                catch (Exception e)
                {
                    throw new Exception($"Error! Period.Parse Failed; Format Invalid; info:{e}");
                }
                idx1 = idx2 + 1;
            }
            return value;

        }
        public static Period Parse(string str)
        {
            str = str.ToLower().Trim();

            int index1 = 0, index2 = 0;
            int d = Parse(str, "d", ref index1, ref index2);
            int h = Parse(str, "h", ref index1, ref index2);
            int m = Parse(str, "m", ref index1, ref index2);
            int s = Parse(str, "s", ref index1, ref index2);

            if (s >= 60)
            {
                m += s / 60;
                s = s % 60;
            }
            if (m >= 60)
            {
                h += m / 60;
                m = m % 60;
            }
            if (h >= 24)
            {
                d += h / 24;
                h = h % 24;
            }

            if ((d >= 0 && h >= 0 && m >= 0 && s >= 0 && h < 24 && m < 60 && s < 60) == false)
            {
                throw new Exception($"Error! Period.Parse Failed; d>0 h=[0,24) m=[0,60) s=[0,60)");
            }

            Period period;
            period.Day = d;
            period.Hour = h;
            period.Minute = m;
            period.Second = s;
            return period;
        }

        public static Period Parse(int time)
        {
            time = Math.Max(time, 0);

            Period period;

            period.Second = time % 60;
            time /= 60;

            period.Minute = time % 60;
            time /= 60;

            period.Hour = time % 24;
            time /= 24;

            period.Day = time;

            return period;
        }

        public bool Equals(Period other)
        {
            return Day == other.Day && Hour == other.Hour && Minute == other.Minute && Second == other.Second;
        }

        public override bool Equals(object obj)
        {
            if (obj == null || (obj is LWH) == false)
            {
                return false;
            }
            return Equals((LWH)obj);
        }

        public override int GetHashCode()
        {
            return Day.GetHashCode() ^ (Hour.GetHashCode() << 2) ^ (Minute.GetHashCode() >> 2) ^ (Second.GetHashCode() >> 1);
        }

        public override string ToString()
        {
            return $"({Day},{Hour},{Minute},{Second})";
        }

        public static implicit operator Period(int time)
        {
            return Parse(time);
        }

        public static explicit operator int(Period period)
        {
            var d = period.Day;
            var h = period.Hour;
            var m = period.Minute;
            var s = period.Second;

            return ((d * 24 + h) * 60 + m) * 60 + s;
        }

    }
}
